package com.xiaoxin.experience.util;

import com.xiaoxin.experience.service.net.model.NetworkInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;

/**
 * @author xiaoxin
 */
public class NetworkUtil
{

    private static final Logger log = LoggerFactory.getLogger(NetworkUtil.class);

    private static final String IP_REGEX = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}";

    private NetworkUtil() {}

    public static NetworkInfo firstNetworkInfo()
    {
        List<NetworkInfo> networkInfos = getNetworkInfos();
        if (CollectionUtil.isEmpty(networkInfos))
        {
            return null;
        }
        return networkInfos.get(0);
    }

    public static String getNetworkCardIp()
    {
        NetworkInfo networkInfo = firstNetworkInfo();
        if (Objects.isNull(networkInfo))
        {
            return null;
        }
        return networkInfo.getIpv4();
    }

    public static boolean isNotLocalHost(String ip)
    {
        return !isLocalHost(ip);
    }

    public static boolean isLocalHost(String ip)
    {
        if("127.0.0.1".equals(ip) || "localhost".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip))
        {
            return true;
        }
        List<NetworkInfo> networkInfos = getNetworkInfos();
        if (CollectionUtil.isEmpty(networkInfos))
        {
            return false;
        }
        for (NetworkInfo networkInfo : networkInfos)
        {
            if (Objects.equals(networkInfo.getIpv4(),ip))
            {
                return true;
            }
        }
        return false;
    }

    public static boolean isIp(String ip)
    {
        if (StringUtil.isBlank(ip))
        {
            return false;
        }

        return ip.matches(IP_REGEX);
    }

    public static List<NetworkInfo> getNetworkInfos()
    {
        List<NetworkInfo> networkInfos = new ArrayList<>();
        try
        {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements())
            {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                byte[] hardwareAddress = networkInterface.getHardwareAddress();
                if (Objects.isNull(hardwareAddress))
                {
                    continue;
                }
                NetworkInfo networkInfo = new NetworkInfo();
                networkInfo.setHardwareAddress(hardwareAddress);
                networkInfo.setNetworkCardName(networkInterface.getName());
                List<InterfaceAddress> interfaceAddresses = networkInterface.getInterfaceAddresses();
                if (CollectionUtil.isEmpty(interfaceAddresses))
                {
                    continue;
                }
                for (InterfaceAddress interfaceAddress : interfaceAddresses)
                {
                    InetAddress address = interfaceAddress.getAddress();
                    if (isIp(address.getHostAddress()))
                    {
                        networkInfo.setIpv4(address.getHostAddress());
                        networkInfo.setInetAddress(address);
                    }
                    else
                    {
                        networkInfo.setIpv6(interfaceAddress.getAddress().getHostAddress());
                    }
                }
                if (StringUtil.isBlank(networkInfo.getIpv4()) || "null".equals(networkInfo.getIpv4()))
                {
                    continue;
                }
                log.debug("local network ipv4 is {}",networkInfo.getIpv4());
                networkInfos.add(networkInfo);
            }
        }
        catch (Exception e)
        {
            log.error("net work info get fail",e);
        }
        return networkInfos;
    }

    /**
     * 将子网掩码长度转换为子网掩码
     */
    public static String intToMask(int i)
    {
        int ip = 0xFFFFFFFF << (32 - i);

        String binaryStr = Integer.toBinaryString(ip);

        StringBuilder buffer = new StringBuilder();

        for (int j = 0; j < 4; j++)
        {
            int beginIndex = j * 8;
            buffer.append(Integer.parseInt(binaryStr.substring(beginIndex, beginIndex + 8), 2)).append(".");
        }

        return buffer.substring(0, buffer.length() - 1);
    }

    /**
     * 将子网掩码转换为长度
     */
    public static int maskToInt(String mask)
    {
        int inetmask = 0;
        String[] ipList = mask.split("\\.");
        for (String s : ipList)
        {
            String str = toBinary(Integer.parseInt(s));

            //统计2进制字符串中1的个数
            int count = 0;
            for (int i = 0; i < str.length(); i++)
            {
                //查找 字符'1'出现的位置
                i = str.indexOf('1', i);
                if (i == -1)
                {
                    break;
                }
                //统计字符出现次数
                count++;
            }
            inetmask += count;
        }
        return inetmask;
    }

    private static String toBinary(int x)
    {
        StringBuilder result = new StringBuilder();
        result.append(x%2);
        x /= 2;
        while(x > 0)
        {
            result.append(x%2);
            x /= 2;
        }
        return result.reverse().toString();
    }
}
